<?php

namespace App\Http\Controllers\Service\Wechat;

use App\Models\Customer\CustomerRelateHmSkin;
use App\Models\Customer\CustomerRelateSkinProductable;
use App\Models\Customer\CustomerRelateWaxSkin;
use App\Models\Customer\Language;
use App\Models\Panx\BodyPosition;
use App\Models\Panx\Category;
use App\Models\Panx\CategoryDescription;
use App\Models\Panx\Product;
use App\Models\Panx\SkinDetector;
use App\Services\Presenters\HmSkinData;
use App\Services\Utils\ApiChecker;
use App\Services\Utils\PanxCollection;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;

class RecommendProductV3Service
{
    use ApiChecker;

    const STORE_ID_DEFAULT = 0; // 默认的店铺id

    /**
     * @param $sub_skin_record
     * @param $skin_detector_id
     * @param $customer_id
     * @param $sex
     * @param int $store_id
     * @return \Illuminate\Database\Eloquent\Collection
     * @throws \Exception
     */
    public function getRecommendProducts($sub_skin_record, $skin_detector_id, $customer_id, $sex, $store_id = self::STORE_ID_DEFAULT)
    {
        if ($skin_detector_id === SkinDetector::ID_WAX) {
            $item_id = $sub_skin_record->itemsid;
            $level_sort = $sub_skin_record->levelsort;
            $data = $this->getRecommendProductsByWaxSkin($item_id, $level_sort, $customer_id, $sex, $store_id);
        } else if ($skin_detector_id === SkinDetector::ID_HM) {
            $flex = $sub_skin_record->flex;
            $oil = $sub_skin_record->oil;
            $water = $sub_skin_record->water;
            $position_id = $sub_skin_record->position;
            $data = $this->getRecommendProductsByHmSkin($flex, $oil, $water, $position_id, $customer_id, $sex, $store_id);
        } else {
            $data = $this->getRecommendProductsByCamSkin();
        }

        return $data;
    }

    /**
     * @param Collection $recommend_products
     * @return Collection
     */
    public function transformRecommendProducts(Collection $recommend_products): Collection
    {
        $group_recommend_products = $recommend_products->groupBy('category_id');
        $language_code = app()->getLocale();
        $language_id = Language::getLanguageIds()[$language_code] ?? Language::LANGUAGE_ID_CN;
        $category_descriptions = CategoryDescription::where(compact('language_id'))
            ->pluck('name', 'category_id')
            ->toArray();

        $group_recommend_products->transform(function (Collection $group_products, $category_id) use($category_descriptions){
            /** @var Category $category */
            $category = $group_products->first()->category;

            $data = [
                'category_id'   => $category_id,
                'category_name' => $category_descriptions[$category_id] ?? null,
                'priority'      => $category->priority,
                'icon_active'   => $category->icon_active,
                'icon'          => $category->icon,
                'products'      => $group_products,
            ];

            $group_products->makeHidden('category');

            return $data;
        });

        return $group_recommend_products->sortByDesc('priority')->values();
    }

    /**
     * @param $item_id
     * @param $level_sort
     * @param $customer_id
     * @param $sex
     * @param $store_id
     * @return \Illuminate\Database\Eloquent\Collection
     * @throws \Exception
     */
    private function getRecommendProductsByWaxSkin($item_id, $level_sort, $customer_id, $sex, $store_id)
    {
        /** @var CustomerRelateWaxSkin[]|Collection $customer_relate_wax_skins */
        $customer_relate_wax_skins = CustomerRelateWaxSkin::getCustomerRelateWaxSkin($item_id, $level_sort, $customer_id, $store_id);

        $recommend_products = $this->getAndAssembleRecommendProducts($customer_relate_wax_skins, $sex, $store_id);

        return $recommend_products;
    }

    /**
     * @param $flex
     * @param $oil
     * @param $water
     * @param $position_id
     * @param $customer_id
     * @param $sex
     * @param $store_id
     * @return \Illuminate\Database\Eloquent\Collection
     * @throws \Exception
     */
    private function getRecommendProductsByHmSkin($flex, $oil, $water, $position_id, $customer_id, $sex, $store_id)
    {
        $water_recommend_products = $this->getRecommendProductsByHmSkinItem(HmSkinData::HM_WATER, $water, $position_id, $customer_id, $sex, $store_id);
        $oil_recommend_products = $this->getRecommendProductsByHmSkinItem(HmSkinData::HM_OIL, $oil, $position_id, $customer_id, $sex, $store_id);
        $flex_recommend_products = $this->getRecommendProductsByHmSkinItem(HmSkinData::HM_FLEX, $flex, $position_id, $customer_id, $sex, $store_id);

        $recommend_products = $water_recommend_products->merge($oil_recommend_products)->merge($flex_recommend_products);

        return $recommend_products;
    }

    /**
     * @param $item_id
     * @param $score
     * @param $position_id
     * @param $customer_id
     * @param $sex
     * @param $store_id
     * @return Collection
     */
    private function getRecommendProductsByHmSkinItem($item_id, $score, $position_id, $customer_id, $sex, $store_id)
    {
        $level_sort = HmSkinData::hmItemLevelSort($item_id, $score);

        /** @var Collection $customer_relate_hm_skins */
        $customer_relate_hm_skins = CustomerRelateHmSkin::getCustomerRelateHmSkin($item_id, $level_sort, $position_id, $customer_id, $store_id);

        $body_position_id = BodyPosition::HM_POSITION_BODY_POSITION_MAP[$position_id];

        $recommend_products = $this->getAndAssembleRecommendProducts($customer_relate_hm_skins, $sex, $store_id, $body_position_id);

        return $recommend_products;
    }

    /**
     * @param Collection $customer_relate_skins
     * @param $sex
     * @param $store_id
     * @param null $body_position_id
     * @return \Illuminate\Database\Eloquent\Collection|array
     */
    private function getAndAssembleRecommendProducts(Collection $customer_relate_skins, $sex, $store_id, $body_position_id = null)
    {
        $customer_relate_skin = $customer_relate_skins->first();

        if (! $customer_relate_skin)  { return new Collection; }

        $productable_ids =  $customer_relate_skins->pluck('id')->toArray();
        $productable_type = class_basename($customer_relate_skin);

        $product_ids = CustomerRelateSkinProductable::getProductIds($productable_ids, $productable_type);

        $recommend_products = $this->getRecommendProductsBySkins($product_ids, $sex, $body_position_id, $store_id);

        return $recommend_products;
    }

    /**
     * @param $product_ids
     * @param $sex
     * @param $body_position_id
     * @param $store_id
     *
     * @return Collection|\Illuminate\Support\Collection|\Tightenco\Collect\Support\Collection
     */
    private function getRecommendProductsBySkins($product_ids, $sex, $body_position_id, $store_id)
    {
        $recommend_products = (new Product)
            ->whereIn('id', $product_ids)
            ->filterStorePivotCustomerProductOnShelf($store_id)
            ->filterSex($sex)
//            ->filterBodyPosition($body_position_id)
            ->filterOnShelf()
            ->get();

        (new PanxCollection($recommend_products))
            ->eachAppend(['tag_names', 'thumb_url', 'link_product', 'brand_name'])
            ->makeHidden(['thumbImage', 'productTags', 'brand']);

        return $recommend_products;
    }

    /**
     * @throws \Exception
     */
    private function getRecommendProductsByCamSkin()
    {
        $this->checkItemExist(false, '手机拍照测肤，不能推荐商品');

        return null;
    }
}